#!/usr/bin/env python
# encoding: utf-8


"""
@file: dingyi.py
@time: 2016/11/1 下午7:31
"""
# 20.三角函数的定义

from mathsolver.functions.root import *
from mathsolver.functions.sanjiao import Jiao as jiao
from sympy import expand_trig, sin, cos, tan, sqrt
from mathsolver.functions.sanjiao import hanshu as hu
from mathsolver.functions.budengshi import common_opers as co

SIN = sympify('y/sqrt(x**2 + y**2)')
COS = sympify('x/sqrt(x**2 + y**2)')
TAN = sympify('y/x')


def known_conds(xx, yy, sym):
    sin_expr = sin(sym)
    sin_value = SIN.subs((('x', xx), ('y', yy)))
    cos_expr = cos(sym)
    cos_value = COS.subs((('x', xx), ('y', yy)))
    tan_expr = tan(sym)
    tan_value = TAN.subs((('x', xx), ('y', yy)))
    return (sin_expr, sin_value), (cos_expr, cos_value), (tan_expr, tan_value)


# 已知角α的终边经过点P(-3,4).求\\frac{sin(π-α)+cos(-α)}{tan(π+α)}的值.
# 结构Point, Poly
class DingYi001(BaseFunction):
    @staticmethod
    def try_cal(f, subs_list):
        """
        尝试求值
        :param f:
        :param subs_list:
        :return:
        """
        tmp_f = f
        while not tmp_f.is_real:
            tmp_f = tmp_f.subs(subs_list)
        return tmp_f

    def solver(self, *args):
        p = args[0]
        f = args[1].sympify()
        trig_symbol = list(f.free_symbols)[0]
        xx, yy = p.value
        sin_pair, cos_pair, tan_pair = known_conds(xx, yy, trig_symbol)
        tmp_f = expand_trig(f)
        f_value = tmp_f.subs((sin_pair, cos_pair, tan_pair))
        self.steps.append(['由角α的终边过点P(%s, %s) 知：' % (xx, yy), ''])
        self.steps.append([new_latex(sin_pair[0]), ' = ' + new_latex(sin_pair[1]) + ','])
        self.steps.append([new_latex(cos_pair[0]), ' = ' + new_latex(cos_pair[1]) + ','])
        self.steps.append([new_latex(tan_pair[0]), ' = ' + new_latex(tan_pair[1]) + ','])
        self.steps.append(['\therefore %s = %s' % (new_latex(f), new_latex(tmp_f)), ' = ' + new_latex(f_value)])
        self.label.add('任意角的三角函数定义')
        self.output.append(BaseNumber(f_value))
        return self


# 已知角θ的终边经过点(5a,12a)(a≠0),则sinθ=.
# 角α的终边经过点P(4a,-3a)(a<0),则sinα+cosα=
# 设a<0,角α的终边经过点P(-3a,4a),那么sinα+2cosα的值等于()
class DingYi002(BaseFunction):
    def solver(self, *args):
        self.label.add('任意角的三角函数定义')
        p = args[0]
        ineq = args[1]
        ineq_inter = co.ineq_expr_list_2_interval(ineq.value)
        f = args[2].sympify()
        trig_symbol = list(f.free_symbols)[0]
        v = trig_symbol
        xx, yy = p.value
        xx, yy = sympify(xx), sympify(yy)
        a_symbol = list(xx.free_symbols)[0] if list(xx.free_symbols) else list(yy.free_symbols)[0]
        if ineq_inter.is_subset(Interval(0, S.Infinity)):  # old:ineq_inter >= 0
            a_symbol = Symbol(str(a_symbol), positive=True)
            xx = xx.subs(str(a_symbol), a_symbol)
            yy = yy.subs(str(a_symbol), a_symbol)
        elif ineq_inter.is_subset(Interval(-S.Infinity, 0)):  # old:ineq_inter <= 0
            a_symbol = Symbol(str(a_symbol), negative=True)
            xx = xx.subs(str(a_symbol), a_symbol)
            yy = yy.subs(str(a_symbol), a_symbol)
        else:
            pass
        r = sqrt(xx ** 2 + yy ** 2)
        sin_pair, cos_pair, tan_pair = known_conds(xx, yy, trig_symbol)
        tmp_f = expand_trig(f)
        f_value = tmp_f.subs((sin_pair, cos_pair, tan_pair))
        self.steps.append(['\\because 角%s的终边经过点P(%s, %s),' % (new_latex(v), new_latex(xx), new_latex(yy)), ineq.printing() + ';'])
        self.steps.append(['\\therefore x = %s, y = %s, r = %s' % (new_latex(xx), new_latex(yy), new_latex(r)), ','])
        self.steps.append(['\\therefore %s = %s, %s = %s, %s =%s' % (
            new_latex(sin_pair[0]), new_latex(sin_pair[1]), new_latex(cos_pair[0]), new_latex(cos_pair[1]), new_latex(tan_pair[0]),
            new_latex(tan_pair[1])), ''])
        self.steps.append(['\\therefore %s = %s = %s' % (new_latex(f), new_latex(tmp_f), new_latex(f_value)), ''])
        self.output.append(BaseValue(f_value))
        return self


# 设角α的终边经过点P(-1,y),tanα=\\frac{1}{2},则y等于()
# 已知角α的终边经过点P(m,-3),cosα=-\\frac{4}{5},则m等于()
class DingYi003(BaseFunction):
    def solver(self, *args):
        self.label.add('任意角的三角函数定义')
        p = args[0]
        eq = args[1]
        l, r = eq.sympify()
        f = l - r
        trig_symbol = list(f.free_symbols)[0]
        xx, yy = p.value
        xx, yy = sympify(xx), sympify(yy)
        other_symbol = list(xx.free_symbols)[0] if list(xx.free_symbols) else list(yy.free_symbols)[0]
        sin_pair, cos_pair, tan_pair = known_conds(xx, yy, trig_symbol)
        tmp_f = f.subs((sin_pair, cos_pair, tan_pair))
        other_symbol_sets = solveset(tmp_f, domain=S.Reals)
        self.steps.append(['\\because %s = %s' % (new_latex(l), new_latex(r)), ''])
        quads = jiao.get_trig_quads(str(type(l)), r)
        l_subs = l.subs((sin_pair, cos_pair, tan_pair))
        other_symbol_interval = solveset(l_subs * r > 0, domain=S.Reals)
        other_symbol_interval_print = co.print_interval(other_symbol_interval, other_symbol)
        self.steps.append(
            ['\\therefore %s为 %s 象限的角' % (new_latex(trig_symbol), str(quads)), ''])
        self.steps.append(
            ['又由角%s的终边经过点P（%s，%s），故%s为第%s象限的角，即%s，' % (
                new_latex(trig_symbol), new_latex(xx), new_latex(yy), new_latex(trig_symbol), new_latex(quads),
                new_latex(other_symbol_interval_print)), ''])
        other_symbol_value = list(filter(lambda v: v in other_symbol_interval, other_symbol_sets))[0]
        self.steps.append(['则%s = %s = %s' % (new_latex(l), new_latex(r), new_latex(l_subs)), ''])
        self.steps.append(['解的 %s = %s' % (new_latex(other_symbol), new_latex(other_symbol_value)), ''])
        self.output.append(BaseNumber(other_symbol_value))
        return self


# 角α的终边落在y=-x上,则sinα的值等于.(没有不等式约束的)
class DingYi004(BaseFunction):
    def solver(self, *args):
        self.label.add('任意角的三角函数定义')
        if len(args) == 2:  # 没有不等式约束的
            line_eq = args[0]
            tan_value = co.line_slope(line_eq)
            f = args[1].sympify()
            trig_symbol = list(f.free_symbols)[0]
            self.steps.append(['角%s终边在直线%s上，所以%s=%s' % (
                new_latex(trig_symbol), line_eq.printing(), new_latex(tan(trig_symbol)), new_latex(tan_value)), ''])
            trig_values = hu.trig_der('T', tan_value)
            eq_sets_print = BaseEqs([[tan(trig_symbol), sin(trig_symbol) / cos(trig_symbol)],
                                     [sin(trig_symbol) ** 2 + cos(trig_symbol) ** 2, 1]]).printing()
            self.steps.append(['\\because ', eq_sets_print])
            sin_values = trig_values['A']
            sin_value = abs(sin_values[0])
            cos_values = trig_values['C']
            cos_value = abs(cos_values[0])
            self.steps.append(
                ['\\therefore ', '%s = \\pm %s, %s =\\pm %s' % (
                    new_latex(sin(trig_symbol)), new_latex(sin_value), new_latex(cos(trig_symbol)), new_latex(cos_value))])
            self.output.append(BaseSymbolValue({sin(trig_symbol): sin_value, cos(trig_symbol): cos_value}))
        elif len(args) == 3:  # 有不等式约束的
            line_eq = args[0]
            tan_value = co.line_slope(line_eq)
            ineq = args[1]
            ineq_interval = co.ineq_expr_list_2_interval(ineq.value)
            f = args[2].sympify()
            trig_symbol = list(f.free_symbols)[0]
            tan_expr = tan(trig_symbol)
            sin_expr = sin(trig_symbol)
            cos_expr = cos(trig_symbol)
            quads = list(jiao.get_trig_quads('tan', tan_value))
            quads = FiniteSet(*quads)
            if ineq_interval.is_subset(Interval(0, S.Infinity)):  # old:ineq_interval > 0
                quads2 = FiniteSet(1, 4)
                quads = quads.intersect(quads2)
            elif ineq_interval.is_subset(Interval(-S.Infinity, 0)):  # old:ineq_interval ineq_interval < 0
                quads2 = FiniteSet(2, 3)
                quads = quads.intersect(quads2)
            sin_quads = filter(lambda t: t[0] in quads, enumerate(jiao.trig_f_quad_pm('sin'), start=1))
            cos_quads = filter(lambda t: t[0] in quads, enumerate(jiao.trig_f_quad_pm('cos'), start=1))
            # 各个三角函数的值
            trig_values = hu.trig_der('T', tan_value)
            sin_values = trig_values['A']
            sin_values = filter(lambda sv: filter(lambda sq: sq[1] * sv > 0, sin_quads), sin_values)
            sin_value = sin_values[0]
            cos_values = trig_values['C']
            cos_values = filter(lambda sv: filter(lambda sq: sq[1] * sv > 0, cos_quads), cos_values)
            cos_value = cos_values[0]
            self.steps.append(
                ['\\because 角%s的终边落在直线%s上，且（%s）' % (new_latex(trig_symbol), line_eq.printing(), ineq.printing()), ''])
            self.steps.append(['\\therefore P在第%s象限，%s=%s，即%s=%s' % (
                new_latex(quads), new_latex(tan_expr), new_latex(tan_value), new_latex(sin_expr),
                new_latex(tan_value * cos_expr)), ''])
            eq_print = BaseEq([sin(trig_symbol) ** 2 + cos(trig_symbol) ** 2, 1]).printing()
            self.steps.append([eq_print, ','])
            self.steps.append(['\\therefore %s = \\pm %s, %s = \\pm %s' % (
                new_latex(sin_expr), new_latex(abs(sin_value)), new_latex(cos_expr), new_latex(abs(cos_value))), ''])
            self.steps.append(['\\because P在第%s象限' % new_latex(quads), '\\therefore %s = %s, %s = %s' % (
                new_latex(sin_expr), new_latex(sin_value), new_latex(cos_expr), new_latex(cos_value))])
        else:
            raise 'fail'
        return self


class DingYi(BaseFunction):
    def solver(self, *args):
        if len(args) == 2 and isinstance(args[0], BasePoint) and isinstance(args[1], BasePoly):
            return DingYi001(verbose=True).solver(*args)
        elif len(args) == 3 and isinstance(args[0], BasePoint) and isinstance(args[1], BaseIneq) \
                and isinstance(args[2], BasePoly):
            return DingYi002(verbose=True).solver(*args)
        elif len(args) == 3 and isinstance(args[0], BasePoint) and isinstance(args[1], (BaseEq, BaseSinEq)) \
                and isinstance(args[2], BaseVariable):
            return DingYi003(verbose=True).solver(*args)
        elif len(args) == 2 and isinstance(args[0], (BaseEq, BaseSinEq)) and isinstance(args[1], BasePoly):
            return DingYi004(verbose=True).solver(*args)
        elif len(args) == 3 and isinstance(args[0], (BaseEq, BaseZhiXian)) and isinstance(args[1], BaseIneq) and \
                isinstance(args[-1], BasePoly):
            return DingYi004(verbose=True).solver(*args)
        pass


if __name__ == '__main__':
    pass
